#include <iostream>
#include <vector>
#include "Specimen.hpp"
#include "ProportionalEnv.hpp"
#include "AckleyFunction.hpp"
#include "EvolutionaryException.hpp"
#include "GeemFunction.hpp"
#include "RosenbrockFunction.hpp"
#include "HimmelblauFunction.hpp"
#include "GoldsteinPriceFunction.hpp"
#include "RastiginFunction.hpp"

//gtest ==================

#include "gtest/gtest.h"
/*#include "src/gtest.cc"
#include "src/gtest-death-test.cc"
#include "src/gtest-filepath.cc"
#include "src/gtest-port.cc"
#include "src/gtest-printers.cc"
#include "src/gtest-test-part.cc"
#include "src/gtest-typed-test.cc"
*/
// /gtest==========================
using std::cout;
using std::cerr;
using std::endl;



/*    
    std::vector<EvalFunction*> functions;
    std::vector<std::string> funNames;
    std::vector<std::vector<Gene> > mins;
    std::vector<std::vector<Gene> > maxs;
    std::vector<std::vector<Gene> > optX;
    std::vector<std::vector<Gene> > optY;

    unsigned dimensions=2;
    functions.resize(6);
    funNames.resize(6);
    mins.resize(6);
    maxs.resize(6);
    optX.resize(6);
    optY.resize(6);
    {
      int i=0;

      functions[i]=new AckleyFunction(dimensions);
      funNames[i]="Ackley";
      mins[i].push_back(-30);
      mins[i].push_back(-30);
      maxs[i].push_back(30);
      maxs[i].push_back(30);
      optX[i].push_back(0);
      optX[i].push_back(0);
      optY[i].push_back(-20-exp(1.f));
      ++i;
	
      functions[i]=new RastiginFunction(dimensions);
      funNames[i]="Rastigin";
      mins[i].push_back(-1);
      mins[i].push_back(-1);
      maxs[i].push_back(1);
      maxs[i].push_back(1);
      optX[i].push_back(0);
      optX[i].push_back(0);
      optY[i].push_back(-2);
      ++i;

      functions[i]=new GeemFunction;
      funNames[i]="Geem";
      mins[i].push_back(-10);
      mins[i].push_back(-10);
      maxs[i].push_back(10);
      maxs[i].push_back(10);
      optX[i].push_back(-0.08984);
      optX[i].push_back(0.71266);
      optY[i].push_back(-1.0316285);
      ++i;

      functions[i]=new GoldsteinPriceFunction;
      funNames[i]="Goldstein - Price";
      mins[i].push_back(-10);
      mins[i].push_back(-10);
      maxs[i].push_back(10);
      maxs[i].push_back(10);
      optX[i].push_back(0.0);
      optX[i].push_back(-1.0);
      optY[i].push_back(3);
      ++i;
	
      functions[i]=new HimmelblauFunction;
      funNames[i]="Himmelblau";
      mins[i].push_back(-5);
      mins[i].push_back(-5);
      maxs[i].push_back(5);
      maxs[i].push_back(5);
      optX[i].push_back(3.0);
      optX[i].push_back(2.0);
      optY[i].push_back(-200);
      ++i;
	
      functions[i]=new RosenbrockFunction;
      funNames[i]="Rosenbrock";
      mins[i].push_back(-30);
      mins[i].push_back(-30);
      maxs[i].push_back(30);
      maxs[i].push_back(30);
      optX[i].push_back(1);
      optX[i].push_back(1);
      optY[i].push_back(0);
      ++i;

    }
   
    cout<<endl<<"functions tests"<<endl;

    // testy pojedyńczych funkcji
    for(unsigned i=0;i<functions.size();++i)
      {
	cout<<funNames[i]<<" function in "<<"optimum point test"<<endl;
	Specimen spec;
	//AckleyFunction ackley(2);
	
	spec.init(dimensions);
	for(unsigned j=0;j<dimensions;++j)
	  {
	    spec[j]=optX[i][j];
	  }
	(*functions[i])(spec);
	
	double result=spec.getFitness();
	cout<<"result: "<<result<<endl;
	cout<<"should be: "<<optY[i].front()<<endl;
	
      }

    cout<<"Environments test"<<endl;
   
    for(unsigned i=0; i<functions.size();++i)
      {
	cout<<funNames[i]<<" function in "<<"proportional environment"<<endl;
	ProportionalEnv propEnv;
	try
	  {
	    propEnv.setMaxPopulation(50);
	      
	    //jesli nie ustawione są ograniczenia na przyrost x i y, 
	    //to nie sa brane pod uwagę
	    propEnv.setFitnessMinChange(0.00001);
	    propEnv.setCoordinatesMinChange(0.00001);
	    // jak na razie strasznie szybko zbiega
	      
	    propEnv.setMaxIterations(1000);
	    propEnv.setMutationProbability(0.3);
	    propEnv.setAlgebraicCrossoverProportion(0.3);
	    propEnv.setDimensionality(functions[i]->getDimensionality());
	    propEnv.setMaxX(maxs[i]);
	    propEnv.setMinX(mins[i]);
	      
	    propEnv.prepare(*functions[i]);
	      
	    //	      propEnv.makeGeneration(geem);
	  }
	catch(EvolutionaryException &ex)
	  {
	    cout<<ex.what()<<endl;
	  }
	  
	try
	  {
	    Specimen theBestOne=propEnv.search(*functions[i]);
	    std::vector<Specimen> children=propEnv.getChildren();

	    for(unsigned j=0;j<theBestOne.getDimensions();++j)
	      {
		cout<<theBestOne[j]<<" ";
	      }
	    cout<<" fitness: "<<theBestOne.getFitness()<<endl<<endl;
	    

	  }
	catch(std::exception &ex)
	  {
	    cerr<<ex.what()<<endl;
	  }
	  
	delete functions[i];
      }
  }
*/

TEST(Specimen,IsWorking)
{
  std::vector<Specimen> spec;
  std::vector<Gene> max,min;

  unsigned noSpecs=5;
  unsigned dims=2;

  max.push_back(10);
  max.push_back(10);
  min.push_back(-10);
  min.push_back(-10);
  
  spec.resize(noSpecs);

    //testing init
  for(unsigned i=0;i<spec.size();++i)
    {
      EXPECT_NO_THROW(spec[i].initRandom(dims,min,max));
    }

  for(unsigned i=0;i<dims;++i)
    {
      EXPECT_NE(spec[0][i],spec[1][i]);
    }


    // for(int i=0;i<2;++i)
    //   {
    // 	std::cout<<spec1[i]<<" ";
    //   }
    // std::cout<<std::endl;

    // for(int i=0;i<2;++i)
    //   {
    // 	std::cout<<spec2[i]<<" ";
    //   }
    // std::cout<<std::endl;

  //   //testing crossover
  //   Specimen spec3,spec4;
  //   spec1.algebraicDetCrossover(spec2,spec3,spec4,0.3);
  //   for(int i=0;i<2;++i)
  //     {
  // 	std::cout<<spec3[i]<<" ";
  //     }
  //   std::cout<<std::endl;

  //   for(int i=0;i<2;++i)
  //     {
  // 	std::cout<<spec4[i]<<" ";
  //     }
  //   std::cout<<std::endl;

  //   //testing mutation
  //   Specimen spec5=spec1.uniformMutation(min,max);
  //   for(int i=0;i<2;++i)
  //     {
  // 	std::cout<<spec5[i]<<" ";
  //     }
  //   std::cout<<std::endl;
  // }
}

int main(int argc, char **argv) {
  ::testing::InitGoogleTest(&argc, argv);
  int retCode=RUN_ALL_TESTS();
  std::cout<<"plum"<<std::endl;
#if defined(WIN32) || defined(_WIN32)
  system("pause");
#endif
  return retCode;
}
